<template>
  <!-- 投资年度计划占比柱状图 -->
  <div class="investPerPieChartPage">
    <div class="chartBox" :id="`perPie-${idName}-chart`"></div>
    <!-- <div class="bgBox"></div> -->
  </div>
</template>

<script setup>
import { ref, reactive, onMounted } from "vue";
import echarts from "@/common/utils/echarts.js";
import {
  getParametricEquation,
  fomatFloat3D,
  changeNumToWan,
} from "../../utils/handelScreen";

const props = defineProps({
  idName: {
    type: String,
    required: true, //必传属性
  },
});

const optionsObj = ref({});

//获取3d丙图的最高扇区的高度
const getHeight3D = (series, height) => {
  series.sort((a, b) => {
    return b.pieData.value - a.pieData.value;
  });
  return (height * 25) / series[0].pieData.value;
};

/*
 * 生成 3D 饼图的配置项
 * @param {Array} pieData - 从接口请求的值；
 * @param {Number} internalDiameterRatio - 圆环内环大小；
 * @returns {Object} - echart 的配置项 option
 */
const getPie3D = (pieData, internalDiameterRatio) => {
  let series = [];
  let sumValue = 0;
  let startValue = 0;
  let endValue = 0;
  let legendData = [];
  let legendBfb = [];
  let k = 1 - internalDiameterRatio;
  pieData.sort((a, b) => {
    return b.value - a.value;
  });
  // 为每一个饼图数据，生成一个 series-surface(参数曲面) 配置
  for (let i = 0; i < pieData.length; i++) {
    sumValue += pieData[i].value;
    let seriesItem = {
      //系统名称
      name:
        typeof pieData[i].name === "undefined" ? `series${i}` : pieData[i].name,
      type: "surface",
      //是否为参数曲面（是）
      parametric: true,
      //曲面图网格线（否）上面一根一根的
      wireframe: {
        show: false,
      },
      pieData: pieData[i],
      pieStatus: {
        selected: false,
        hovered: false,
        k: k,
      },
    };

    //曲面的颜色、不透明度等样式。
    if (typeof pieData[i].itemStyle != "undefined") {
      let itemStyle = {};
      typeof pieData[i].itemStyle.color != "undefined"
        ? (itemStyle.color = pieData[i].itemStyle.color)
        : null;
      typeof pieData[i].itemStyle.opacity != "undefined"
        ? (itemStyle.opacity = pieData[i].itemStyle.opacity)
        : null;
      seriesItem.itemStyle = itemStyle;
    }
    series.push(seriesItem);
  }

  // 使用上一次遍历时，计算出的数据和 sumValue，调用 getParametricEquation 函数，
  // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation，也就是实现每一个扇形。
  legendData = [];
  legendBfb = [];
  for (let i = 0; i < series.length; i++) {
    endValue = startValue + series[i].pieData.value;
    series[i].pieData.startRatio = startValue / sumValue;
    series[i].pieData.endRatio = endValue / sumValue;
    series[i].parametricEquation = getParametricEquation(
      series[i].pieData.startRatio,
      series[i].pieData.endRatio,
      false,
      false,
      k,
      series[i].pieData.value
    );
    startValue = endValue;
    let bfb = fomatFloat3D(series[i].pieData.value / sumValue, 4);
    legendData.push({
      name: series[i].name,
      value: bfb,
    });
    legendBfb.push({
      name: series[i].name,
      value: bfb,
    });
  }
  //第二个参数 - 设置环形的高度
  let boxHeight = getHeight3D(series, 8); //通过传参设定3d饼/环的高度
  // 准备待返回的配置项，把准备好的 legendData、series 传入。
  let option = {
    //图例组件
    legend: {
      data: legendData,
      //图例列表的布局朝向。
      // orient: "vertical",
      orient: "horizontal",
      // left: 250,
      // top: 90,
      left: 0,
      top: 25,
      //图例文字每项之间的间隔
      itemGap: 15,
      textStyle: {
        color: "#D3E3FF",
        fontSize: 14,
        // [上, 右, 下, 左]
        padding: [0, 0, 0, 8],
      },
      show: true,
      icon: "rect",
      itemWidth: 8,
      itemHeight: 8,
      //格式化图例文本（我是数值什么显示什么）
      formatter: function (name) {
        let target;
        for (let i = 0, l = pieData.length; i < l; i++) {
          if (pieData[i].name == name) {
            target = pieData[i].value;
          }
        }
        return `${name}：` + changeNumToWan(target) + "万元";
      },
    },
    //移动上去提示的文本内容
    tooltip: {
      backgroundColor: "rgba(50,50,50,0.5)",
      textStyle: {
        color: "#fff",
      },
      formatter: (params) => {
        if (
          params.seriesName !== "mouseoutSeries" &&
          params.seriesName !== "pie2d"
        ) {
          let bfb = (
            (option.series[params.seriesIndex].pieData.endRatio -
              option.series[params.seriesIndex].pieData.startRatio) *
            100
          ).toFixed(2);
          return (
            `${params.seriesName}占比：<br/>` +
            `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
            `${bfb} %`
          );
        }
      },
    },
    //这个可以变形
    xAxis3D: {
      min: -1,
      max: 1,
    },
    yAxis3D: {
      min: -1,
      max: 1,
    },
    zAxis3D: {
      min: -1,
      max: 1,
    },
    //以下是修改样式的重点
    grid3D: {
      show: false,
      boxHeight: boxHeight, //圆环的高度
      //这是饼图的位置
      // top: "0%",
      // left: "-18%",
      top: "5%",
      left: "-10%",
      viewControl: {
        //3d效果可以放大、旋转等
        alpha: 30, //角度(这个很重要 调节角度的)
        distance: 170, //调整视角到主体的距离，类似调整zoom(这是整体大小)
        rotateSensitivity: 0, //设置为0无法旋转
        zoomSensitivity: 0, //设置为0无法缩放
        panSensitivity: 0, //设置为0无法平移
        autoRotate: true, //自动旋转
      },
    },
    series: series,
  };
  return option;
};

// 在父组件中调用
const initPerPieChart = (getPerValObj) => {
  let investPerPieChart = echarts.init(
    document.getElementById(`perPie-${props.idName}-chart`)
  );
  // 调用方法，传入参数，生成饼图配置项
  optionsObj.value = getPie3D(
    [
      {
        name: "固投",
        value: getPerValObj.investAmount,
        itemStyle: {
          // 透明度
          opacity: 1,
          // 扇形颜色
          color: "#2DCEA3",
        },
      },
      {
        name: "股权",
        value: getPerValObj.shareholdAmount,
        itemStyle: {
          // 透明度
          opacity: 1,
          // 扇形颜色
          color: "#2D97E8",
        },
      },
    ],
    0.9 // 可做为调整内环大小
  );
  setTimeout(() => {
    investPerPieChart.setOption(optionsObj.value);
    bindListen(investPerPieChart);
    return investPerPieChart
  }, 300);
};

// 监听鼠标事件，实现饼图选中效果（单选），近似实现高亮（放大）效果。
const bindListen = (myChart) => {
  let selectedIndex = "";
  let hoveredIndex = "";
  // 监听点击事件，实现选中效果（单选）
  myChart.on("click", function (params) {
    // 从 option.series 中读取重新渲染扇形所需的参数，将是否选中取反。
    let isSelected =
      !optionsObj.value.series[params.seriesIndex].pieStatus.selected;
    let isHovered =
      optionsObj.value.series[params.seriesIndex].pieStatus.hovered;
    let k = optionsObj.value.series[params.seriesIndex].pieStatus.k;
    let startRatio =
      optionsObj.value.series[params.seriesIndex].pieData.startRatio;
    let endRatio = optionsObj.value.series[params.seriesIndex].pieData.endRatio;
    // 如果之前选中过其他扇形，将其取消选中（对 option 更新）
    if (selectedIndex !== "" && selectedIndex !== params.seriesIndex) {
      optionsObj.value.series[selectedIndex].parametricEquation =
        getParametricEquation(
          optionsObj.value.series[selectedIndex].pieData.startRatio,
          optionsObj.value.series[selectedIndex].pieData.endRatio,
          false,
          false,
          k,
          optionsObj.value.series[selectedIndex].pieData.value
        );
      optionsObj.value.series[selectedIndex].pieStatus.selected = false;
    }
    // 对当前点击的扇形，执行选中/取消选中操作（对 option 更新）
    optionsObj.value.series[params.seriesIndex].parametricEquation =
      getParametricEquation(
        startRatio,
        endRatio,
        isSelected,
        isHovered,
        k,
        optionsObj.value.series[params.seriesIndex].pieData.value
      );
    optionsObj.value.series[params.seriesIndex].pieStatus.selected = isSelected;
    // 如果本次是选中操作，记录上次选中的扇形对应的系列号 seriesIndex
    isSelected ? (selectedIndex = params.seriesIndex) : null;
    // 使用更新后的 option，渲染图表
    myChart.setOption(optionsObj.value);
  });
  // 监听 mouseover，近似实现高亮（放大）效果
  myChart.on("mouseover", function (params) {
    // 准备重新渲染扇形所需的参数
    let isSelected;
    let isHovered;
    let startRatio;
    let endRatio;
    let k;
    // 如果触发 mouseover 的扇形当前已高亮，则不做操作
    if (hoveredIndex === params.seriesIndex) {
      return;
      // 否则进行高亮及必要的取消高亮操作
    } else {
      // 如果当前有高亮的扇形，取消其高亮状态（对 option 更新）
      if (hoveredIndex !== "") {
        // 从 option.series 中读取重新渲染扇形所需的参数，将是否高亮设置为 false。
        isSelected = optionsObj.value.series[hoveredIndex].pieStatus.selected;
        isHovered = false;
        startRatio = optionsObj.value.series[hoveredIndex].pieData.startRatio;
        endRatio = optionsObj.value.series[hoveredIndex].pieData.endRatio;
        k = optionsObj.value.series[hoveredIndex].pieStatus.k;
        // 对当前点击的扇形，执行取消高亮操作（对 option 更新）
        optionsObj.value.series[hoveredIndex].parametricEquation =
          getParametricEquation(
            startRatio,
            endRatio,
            isSelected,
            isHovered,
            k,
            optionsObj.value.series[hoveredIndex].pieData.value
          );
        optionsObj.value.series[hoveredIndex].pieStatus.hovered = isHovered;
        // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
        hoveredIndex = "";
      }
      // 如果触发 mouseover 的扇形不是透明圆环，将其高亮（对 option 更新）
      if (
        params.seriesName !== "mouseoutSeries" &&
        params.seriesName !== "pie2d"
      ) {
        // 从 option.series 中读取重新渲染扇形所需的参数，将是否高亮设置为 true。
        isSelected =
          optionsObj.value.series[params.seriesIndex].pieStatus.selected;
        isHovered = true;
        startRatio =
          optionsObj.value.series[params.seriesIndex].pieData.startRatio;
        endRatio = optionsObj.value.series[params.seriesIndex].pieData.endRatio;
        k = optionsObj.value.series[params.seriesIndex].pieStatus.k;
        // 对当前点击的扇形，执行高亮操作（对 option 更新）
        optionsObj.value.series[params.seriesIndex].parametricEquation =
          getParametricEquation(
            startRatio,
            endRatio,
            isSelected,
            isHovered,
            k,
            optionsObj.value.series[params.seriesIndex].pieData.value + 5
          );
        optionsObj.value.series[params.seriesIndex].pieStatus.hovered =
          isHovered;
        // 记录上次高亮的扇形对应的系列号 seriesIndex
        hoveredIndex = params.seriesIndex;
      }
      // 使用更新后的 option，渲染图表
      myChart.setOption(optionsObj.value);
    }
  });
  // 修正取消高亮失败的 bug
  myChart.on("globalout", function () {
    // 准备重新渲染扇形所需的参数
    let isSelected;
    let isHovered;
    let startRatio;
    let endRatio;
    let k;
    if (hoveredIndex !== "") {
      // 从 option.series 中读取重新渲染扇形所需的参数，将是否高亮设置为 true。
      isSelected = optionsObj.value.series[hoveredIndex].pieStatus.selected;
      isHovered = false;
      k = optionsObj.value.series[hoveredIndex].pieStatus.k;
      startRatio = optionsObj.value.series[hoveredIndex].pieData.startRatio;
      endRatio = optionsObj.value.series[hoveredIndex].pieData.endRatio;
      // 对当前点击的扇形，执行取消高亮操作（对 option 更新）
      optionsObj.value.series[hoveredIndex].parametricEquation =
        getParametricEquation(
          startRatio,
          endRatio,
          isSelected,
          isHovered,
          k,
          optionsObj.value.series[hoveredIndex].pieData.value
        );
      optionsObj.value.series[hoveredIndex].pieStatus.hovered = isHovered;
      // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
      hoveredIndex = "";
    }
    // 使用更新后的 option，渲染图表
    myChart.setOption(optionsObj.value);
  });
};

defineExpose({
  initPerPieChart,
});
</script>

<style lang="scss" scoped>
.investPerPieChartPage {
  width: 100%;
  height: 100%;
  .chartBox {
    width: 100%;
    height: 100%;
    background: url("@/assets/screenImg/commonImg/3DPieBg.png") no-repeat;
    background-size: 65% 50%;
    // background-position: 0px 84px
    background-position: 30px 95px;
  }
}
</style>
